#ifndef     __STORE_H
#define     __STORE_H

#include "../driver/flash.h"
#include "./error.h"
#include "./md5.h"
#include <string.h>

namespace utils {

namespace impl {

template <typename T>
struct Box {
    T val;
    uint8_t md5_sum[16];

    bool verify() const {
        uint8_t sum[16];
        md5::sum(&val, sizeof (T), sum);
        return memcmp(md5_sum, sum, 16) == 0;
    }

    void update() {
        md5::sum(&val, sizeof (T), md5_sum);
    }
};

}

template <typename T, uint32_t Addr>
class Store {

public:
    
    inline T* operator->() {
        return &m_box.val;
    }

    Error load() {
        using namespace driver;

        Error err;
        flash::read(Addr, &m_box, sizeof(m_box));
        bool ret = m_box.verify();
        if (!ret) {
            m_box.val.reset();
            err = ec::FLASH_CHECK_FAIL;
        }
        return err;
    }

    inline Error erase() {
		using namespace driver;
        return flash::erase(Addr, sizeof (m_box));
    }

    Error save() {
        using namespace driver;
        
        Error err = erase();
        if (err) {
            goto finish;
        }
        m_box.update();

        err = flash::write(Addr, &m_box, sizeof (m_box));
        if (err) {
            goto finish;
        }
    finish:
        return err;
    }

private:
    impl::Box<T> m_box;
};

}


#endif
